package com.buaa.aiguangxi.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.buaa.aiguangxi.service.UserService;
import com.buaa.aiguangxi.pojo.User;
import com.buaa.aiguangxi.utils.JwtTokenUtil;
import lombok.SneakyThrows;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;

public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
    private AuthenticationManager authenticationManager;
    private UserService userService;
    public JWTAuthenticationFilter(AuthenticationManager authenticationManager,UserService userService){
        this.authenticationManager=authenticationManager;
        this.userService=userService;
    }
    @SneakyThrows
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response){
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        if (userService.getUserByName(username)==null){
            PrintWriter out = response.getWriter();
            Map<String, Object> map = new HashMap<>();
            map.put("status", -1);
            map.put("msg","用户名不存在");
            map.put("success",false);
            out.write(new ObjectMapper().writeValueAsString(map));
            out.flush();
            out.close();
            return null;
        }
        User user=userService.getUserByName(username);
        PasswordEncoder passwordEncoder=new BCryptPasswordEncoder();
        List<SimpleGrantedAuthority> authorities=new ArrayList<>();
        authorities.add(new SimpleGrantedAuthority("user"));
        if (!passwordEncoder.matches(password,user.getUserPassword())){
            PrintWriter out = response.getWriter();
            Map<String, Object> map = new HashMap<>();
            map.put("success", false);
            map.put("msg","用户名或密码错误");
            out.write(new ObjectMapper().writeValueAsString(map));
            out.flush();
            out.close();
            return null;
        }
        UsernamePasswordAuthenticationToken token=new UsernamePasswordAuthenticationToken(username, password,authorities);
        token.setDetails(user);
        return authenticationManager.authenticate(
                token
        );
    }
    @Override
    protected void successfulAuthentication(HttpServletRequest request,
                                            HttpServletResponse response, FilterChain chain, Authentication authResult
    ) throws IOException, ServletException {
        UserDetails jwtUser = (UserDetails) authResult.getPrincipal();
        Collection<? extends GrantedAuthority> authorities = jwtUser.getAuthorities();
        String role = "";
        for(GrantedAuthority authority : authorities){
            role = authority.getAuthority();
        }

        String token = JwtTokenUtil.createToken(jwtUser.getUsername(), role,userService.getUserByName(jwtUser.getUsername()).getUserid(), false);
        PrintWriter out = response.getWriter();
        Map<String, Object> map = new HashMap<>();
        map.put("success", true);
        map.put("msg","");
        map.put("Authorization", token);  // 登录成功的对象
        out.write(new ObjectMapper().writeValueAsString(map));
        out.flush();
        out.close();
        //返回创建成功的token
        //但是这里创建的token只是单纯的token，按照jwt的规定，
        //最后请求的格式应该是 “Bearer token“。
        response.addHeader(JwtTokenUtil.TOKEN_HEADER, JwtTokenUtil.TOKEN_PREFIX + token);
    }

    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
                                              AuthenticationException failed) throws IOException, ServletException {
        response.getWriter().write("authentication failed, reason: " + failed.getMessage());
    }
}
